package com.mjk.common.tools.properties;

import com.google.common.base.Preconditions;

import com.mjk.common.base.constns.BeeCommonConstns;
import com.mjk.common.base.scope.annotation.BeeRefreshScope;
import com.mjk.common.tools.properties.annotation.BeeProperties;
import com.mjk.common.tools.springextend.BeeApplicationListener;
import com.mjk.common.util.ClassUtil;
import com.mjk.common.util.PropertyUtil;
import com.mjk.common.util.ReflectionUtils;
import com.mjk.common.util.StrUtils;
import lombok.Getter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.env.Environment;

import java.util.*;
import java.util.Map.Entry;

@Configuration
@PropertySource(value = "classpath:third.properties",ignoreResourceNotFound=true)
public class PropertiesConfig implements EnvironmentAware,BeanDefinitionRegistryPostProcessor
	, BeeApplicationListener {
	private  String scopeHeader = "scopedTarget.";
	private  String prefix = "ld.thrid.";
	BeanDefinitionRegistry registry;
	//待实例化数据
    final Map<String,Map<String, Object>> instanceMap = new HashMap<>();
	
	Map<String, Class<?>> thridMap = new HashMap<>();
	
	@Getter
    final List<String> beans = new ArrayList<>();
	Environment environment;
	@SuppressWarnings("unchecked")
	@Override
	public void setEnvironment(Environment environment) {	
		
		this.environment = environment;
		thridMap = getPropertiesMap();
		for(Entry<String, Class<?>> entry : thridMap.entrySet()){
			Map<String, Object> props = PropertyUtil.handle(environment, prefix + entry.getKey(), Map.class);
			Preconditions.checkState(!props.isEmpty(), "Wrong "+entry.getKey()+" properties!");				
			if(entry.getValue().getAnnotation(BeeRefreshScope.class)!=null) {
				instanceMap.put(scopeHeader+StrUtils.toLowerCaseFirstOne(entry.getValue().getSimpleName()), props);
			}else {
				instanceMap.put(StrUtils.toLowerCaseFirstOne(entry.getValue().getSimpleName()), props);
			}
		}
	}
	
	public Map<String, Class<?>> getPropertiesMap(){
		Map<String, Class<?>> props = new HashMap<>();
		Set<Class<?>> clazzs = cn.hutool.core.util.ClassUtil.scanPackageByAnnotation(BeeCommonConstns.BASE_PACKAGE, BeeProperties.class);
//		Set<Class<?>> clazzs = ClassUtil.scanPackageByAnnotation(BeeCommonConstns.BASE_PACKAGE, true, BeeProperties.class);
		for(Class<?> clazz : clazzs){
			BeeProperties anno = clazz.getAnnotation(BeeProperties.class);
			if(null!=anno){
				props.put(anno.propertiefix(), clazz);
			}
		}
		return props;
	}
 
	@Override
	public void postProcessBeanFactory(
			ConfigurableListableBeanFactory beanFactory) throws BeansException {
		//AbstractBeanDefinition beanDefinition;
		for(Entry<String, Class<?>> entry : thridMap.entrySet()){
//			BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(entry.getValue());
			if(entry.getValue().getAnnotation(BeeRefreshScope.class)!=null) {
				beans.add(scopeHeader+StrUtils.toLowerCaseFirstOne(entry.getValue().getSimpleName()));
//				builder.setScope(BeanRefreshScope.SCOPE_REFRESH);
			}else {
                beans.add(StrUtils.toLowerCaseFirstOne(entry.getValue().getSimpleName()));
			}
		}
	}

	@Override
	public void postProcessBeanDefinitionRegistry(
			BeanDefinitionRegistry registry) throws BeansException {
		this.registry = registry;
	}
	
	@Override
	public void doApplicationEvent(ContextRefreshedEvent event) {
		ApplicationContext context = event.getApplicationContext();
		//RedisTemplate redisTemplate = context.getBean(RedisTemplate.class);
		for(String beanName : beans){	
			Object bean = context.getBean(beanName);
			BeeProperties propertis = bean.getClass().getAnnotation(BeeProperties.class);
			BeeRefreshScope refresh = bean.getClass().getAnnotation(BeeRefreshScope.class);
			if(context.containsBean(beanName)){
				for(Entry<String,Object> field : instanceMap.get(beanName).entrySet()){
					if(propertis!=null &&refresh!=null) {
						//Object vaule = RedisHashUtils.get(redisTemplate, "conf_content", prefix+propertis.propertiefix()+"."+field.getKey());
						//if(ObjectUtils.isNotEmpty(vaule)) {
						//	ReflectionUtils.setFieldValue(bean, field.getKey(), vaule);
						//}else {
							ReflectionUtils.setFieldValue(bean, field.getKey(), field.getValue());
						//}
					}else {
						ReflectionUtils.setFieldValue(bean, field.getKey(), field.getValue());
					}
				}
			}
		}
	}

	public Map<String, Map<String, Object>> getInstanceMap() {
		for(Entry<String, Class<?>> entry : thridMap.entrySet()){
			Map<String, Object> props = PropertyUtil.handle(environment, prefix + entry.getKey(), Map.class);
			Preconditions.checkState(!props.isEmpty(), "Wrong "+entry.getKey()+" properties!");	
			if(entry.getValue().getAnnotation(BeeRefreshScope.class)!=null) {
				instanceMap.put(scopeHeader+StrUtils.toLowerCaseFirstOne(entry.getValue().getSimpleName()), props);
			}else {
				instanceMap.put(StrUtils.toLowerCaseFirstOne(entry.getValue().getSimpleName()), props);
			}
		}
		return instanceMap;
	}

}
